package com.hfzy.ihk.web.linkcall.biz.flow.config;

import com.hfzy.ihk.common.constants.GlobalStatic;
import com.hfzy.ihk.common.core.elasticsearch.ElasticsearchOperation;
import com.hfzy.ihk.common.core.elasticsearch.EsQueryUtils;
import com.hfzy.ihk.common.core.elasticsearch.anotations.BestDoSupport;
import com.hfzy.ihk.common.core.elasticsearch.base.BestDoContextHolder;
import com.hfzy.ihk.common.core.elasticsearch.service.EsBaseServiceImpl;
import com.hfzy.ihk.common.util.Utils;
import com.hfzy.ihk.common.web.WebResult;
import com.hfzy.ihk.facade.linkcall.entity.flow.config.CustomerAnswerWay;
import com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingFlow;
import com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingFlowStep;
import com.hfzy.ihk.facade.linkcall.enums.*;
import com.hfzy.ihk.web.linkcall.dao.SpeakingFlowRepository;
import com.hfzy.ihk.web.linkcall.support.annotation.PreProcessParam;
import com.hfzy.ihk.web.linkcall.support.annotation.PushMsgToAIService;
import com.hfzy.ihk.web.linkcall.utils.UserUtils;
import com.hfzy.ihk.web.linkcall.utils.WebResultUtils;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: ouyicong
 * @Date: 2018/8/13 16:22
 * @Description:
 *  * 话术流程
 * 注：
 *  多伦回话也是一个流程
 *  Biz业务逻辑层
 */

@Service
public class SpeakingFlowBiz extends EsBaseServiceImpl<SpeakingFlow> {

    Logger logger = LoggerFactory.getLogger(SpeakingFlowBiz.class);

    @Autowired
    private SpeakingFlowRepository speakingFlowRepository;

    @Autowired
    private SpeakingFlowStepBiz speakingFlowStepBiz;

    @Autowired
    private CustomerAnswerWayBiz customerAnswerWayBiz;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    protected ElasticsearchCrudRepository getReposity() {

        return speakingFlowRepository;
    }

    /**
     *
     * 功能描述:查询所有SpeakingFlow
     *
     * @param:
     * @return: List<SpeakingFlowBiz> 所有的SpeakingFlowBiz
     * @auther:
     * @date: 2018/8/13
     */
    public List<SpeakingFlow> searchAllSpeakingFlow(){
        try {
            //构建查询对象SearchQuery
            SearchQuery searchQuery =new  NativeSearchQueryBuilder().
                                     withQuery(QueryBuilders.matchAllQuery()).
                                     build();
            //用spring-data-elasticsearch进行查询

            return elasticsearchTemplate.queryForList(searchQuery,SpeakingFlow.class);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("SpeakingFlow查询全部出错",e);
            return null;
        }

    }

    /**
     *
     * 功能描述:根据map里面的参数查询
     *
     * @param: []
     * @return: java.util.List<com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingFlow>
     * @auther:
     * @date: 2018/8/17
     */
    public List<SpeakingFlow> searchSpeakingFlowByField(Map<String,Object> paramMap){
            List<SpeakingFlow> speakingFlows = null;
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

            if (paramMap==null||paramMap.size()==0){

                boolQueryBuilder.must(EsQueryUtils.matchAllQuerty());

            }
            if(paramMap.containsKey("flowName")){

                boolQueryBuilder.must(EsQueryUtils.wildcardQuery("flowName","*"+paramMap.get("flowName")+"*"));
            }

            nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

            NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();

            speakingFlows = elasticsearchTemplate.queryForList(searchQuery, SpeakingFlow.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return speakingFlows;
    }




    /**
     *
     * 功能描述:根据map里面的参数查询
     *
     * @param: []
     * @return: java.util.List<com.hfzy.ihk.facade.linkcall.entity.flow.config.SpeakingFlow>
     * @auther:
     * @date: 2018/8/17
     */
    public List<SpeakingFlow> searchFilterSpeakingFlowByField(Map<String,Object> paramMap){
        List<SpeakingFlow> speakingFlows = new ArrayList<>();
        try {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();


            if (paramMap==null||paramMap.size()==0){

                boolQueryBuilder.must(EsQueryUtils.matchAllQuerty());

            }
            if(paramMap.containsKey("flowName")){

                boolQueryBuilder.must(EsQueryUtils.wildcardQuery("flowName","*"+paramMap.get("flowName")+"*"));
            }

           if(paramMap.containsKey("flowType")){

                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("flowType", paramMap.get("flowType"));

                boolQueryBuilder.must(termQueryBuilder);
            }

            if(paramMap.containsKey("packageId")){

                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("packageId", paramMap.get("packageId"));

                boolQueryBuilder.must(termQueryBuilder);
            }


            Iterator<SpeakingFlow> iterator = speakingFlowRepository.search(boolQueryBuilder).iterator();

            while (iterator.hasNext()){

                speakingFlows.add(iterator.next());

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return speakingFlows;
    }



    @PreProcessParam
    public Page<SpeakingFlow> getSpeakingFlowByPage(Map<String,String> params){
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        int pageNum = Integer.valueOf(params.get("page"))-1;
        int pageSize = Integer.valueOf(params.get("pageSize"));
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        return getSpeakingFlowByCondition(pageNum,pageSize,boolQueryBuilder,fieldSortBuilder);
    }


    public Page<SpeakingFlow> getSpeakingFlowByCondition(int pageNum,int pageSize,BoolQueryBuilder boolQueryBuilder,FieldSortBuilder fieldSortBuilder){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withSort(fieldSortBuilder).withPageable(PageRequest.of(pageNum,pageSize));
        return speakingFlowRepository.search(builder.build());
    }

    public SpeakingFlow getSpeakingFlowById(String id){
        Map params = new HashMap();
        params.put("id",id);
        List<SpeakingFlow> speakingFlows = getSpeakingFlowList(params);
        return Utils.getFirst(speakingFlows);
    }

    @PreProcessParam
    public List<SpeakingFlow> getSpeakingFlowList(Map<String,String> params){
        List<SpeakingFlow> speakingFlows = null;
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        Iterator<SpeakingFlow> iterator = speakingFlowRepository.search(boolQueryBuilder).iterator();
        if (iterator != null) {
            speakingFlows = new ArrayList<SpeakingFlow>();
            while (iterator.hasNext()) {
                SpeakingFlow next = iterator.next();
                speakingFlows.add(next);
            }
        }
        return speakingFlows;

    }


    public List<SpeakingFlow> getSpeakingFlowListByPackageId(String packageId){
        Map params = new HashMap();
        params.put("packageId",packageId);
        List<SpeakingFlow> speakingFlowList = getSpeakingFlowList(params);
        speakingFlowList = speakingFlowList.stream().sorted(Comparator.comparing(SpeakingFlow::getSortNum)).collect(Collectors.toList());
      /*  BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("sortNum").order(SortOrder.ASC);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withSort(fieldSortBuilder)
                .build();
        speakingFlowList = elasticsearchTemplate.queryForList(searchQuery,SpeakingFlow.class);*/
        return speakingFlowList;
    }

    public List<SpeakingFlow> getSpeakingFlowListByPackageIdType(String packageId, SpeakingFlowType speakingFlowType){
        Map params = new HashMap();
        params.put("packageId",packageId);
        params.put("flowType",speakingFlowType.name());
        List<SpeakingFlow> speakingFlowList = getSpeakingFlowList(params);
        speakingFlowList = speakingFlowList.stream().sorted(Comparator.comparing(SpeakingFlow::getSortNum)).collect(Collectors.toList());
        /*List<SpeakingFlow> speakingFlowList = null;
        BoolQueryBuilder boolQueryBuilder = getQueryBuilderByParams(params);
        //添加排序字段
        FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("sortNum").order(SortOrder.ASC);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withSort(fieldSortBuilder)
                .build();
        speakingFlowList = elasticsearchTemplate.queryForList(searchQuery,SpeakingFlow.class);;*/
        return speakingFlowList;
    }

    public BoolQueryBuilder getQueryBuilderByParams(Map<String,String> params){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Iterator entries = params.entrySet().iterator();
        while (entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            String key = entry.getKey().toString();
            switch (key){
                case "flowName":
                    QueryBuilder projectName = EsQueryUtils.wildcardQuery("flowName", "*"+params.get("flowName")+"*");
                    EsQueryUtils.boolQuery(boolQueryBuilder, EsQueryUtils.BoolType.MUST, projectName);
                    break;
                case "id":
                    QueryBuilder queryBuilder = EsQueryUtils.termQuery("id",params.get("id"));
                    boolQueryBuilder.must(queryBuilder);
                    break;
                case "packageId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("packageId",params.get("packageId")));
                    break;
                case "flowType":
                    boolQueryBuilder.must( EsQueryUtils.termQuery("flowType", params.get("flowType")));
                    break;
                case "createUserId":
                    boolQueryBuilder.must(EsQueryUtils.termQuery("createUserId",params.get("createUserId")));
                    break;
                default:
                    break;
            }
        }
        return boolQueryBuilder;
    }

    @PushMsgToAIService
    public WebResult addSpeakingFlow(SpeakingFlow speakingFlow) throws Exception {
        WebResult webResult = null;
        speakingFlow.setCreateTime(new Date());
        speakingFlow.setId(UUIDs.base64UUID());
        speakingFlow.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);
        /**
         * 创建默认分支
         * */
        List<CustomerAnswerWay> customerAnswerWays = customerAnswerWayBiz.getDefalutCustomerAnswerWay();
        if(customerAnswerWays!=null && !customerAnswerWays.isEmpty()){
            for(CustomerAnswerWay customerAnswerWay:customerAnswerWays){
                CustomerAnswerWay cloneCustomer = (CustomerAnswerWay)Utils.cloneObject(customerAnswerWay);
                cloneCustomer.setFlowId(speakingFlow.getId());
                cloneCustomer.setFlowStepId("0");
                customerAnswerWayBiz.addCustomerAnswerWay(cloneCustomer);
            }
        }
        speakingFlowRepository.save(speakingFlow);
        webResult = WebResultUtils.getSuccessCharWebResult("",0,null);
        return webResult;
    }

    @PushMsgToAIService
    public WebResult saveSpeakingFlow(SpeakingFlow speakingFlow){
        WebResult webResult = null;
        if(!Utils.isNullString(speakingFlow.getId())){
            speakingFlow.setModTime(new Date());
            update(speakingFlow);
        }else{
            webResult = WebResultUtils.getFailCharWebResult("参数异常");
        }
        webResult = WebResultUtils.getSuccessCharWebResult("",0,null);
        return webResult;
    }

    @BestDoSupport
    @PushMsgToAIService
    public WebResult deleteSpeakingFlowById(String id){
        WebResult webResult = null;
        String txId = BestDoContextHolder.getTransactionId();
        if(txId!=null) {//次要操作
            List<SpeakingFlowStep> speakingFlowStepList = speakingFlowStepBiz.getSpeakingFlowStepByFlowId(id);//根据流程id获取 原有的流程步骤
            if(speakingFlowStepList!=null && !speakingFlowStepList.isEmpty()){
                ElasticsearchOperation operation = new ElasticsearchOperation(txId,
                        LinkCallTables.SPEAKING_FLOW_STEP.getTableName(),
                        LinkCallOperations.delSpeakingFlowSteps.getOperationName(),
                        speakingFlowStepList);
                BestDoContextHolder.addOperation(operation);
            }
        }
        //主操作
        boolean flag = deleteById(id);
        if(flag == true){
            webResult = WebResultUtils.getSuccessCharWebResult("",0,null);
        }else{
            webResult = WebResultUtils.getFailCharWebResult("");
        }
        return  webResult;
    }


    @BestDoSupport
    @PushMsgToAIService
    public  WebResult saveFlows(SpeakingFlow speakingFlow, List<SpeakingFlowStep> speakingFlowSteps){
        WebResult webResult = null;
        Date createTime = new Date();
        String txId = BestDoContextHolder.getTransactionId();
        if(txId!=null) {//次要操作
            List<SpeakingFlowStep> oldBelongFlowSteps = speakingFlowStepBiz.getSpeakingFlowStepByFlowId(speakingFlow.getId());//根据流程id获取 原有的流程步骤
            List<SpeakingFlowStep> needDelFlowSteps = new ArrayList<SpeakingFlowStep>();
            if(oldBelongFlowSteps!=null && oldBelongFlowSteps.isEmpty()){
                System.out.println(oldBelongFlowSteps.size());
            }
            List<String> speakingFlowStepIds = new ArrayList<String>();
            speakingFlowSteps.forEach(sfs->{
                sfs.setCreateTime(new Date());
                sfs.setPackageId(speakingFlow.getPackageId());
                sfs.setFlowId(speakingFlow.getId());
                sfs.setCreateUserId(UserUtils.getCurrentUserId()!=null?UserUtils.getCurrentUserId():0l);
                speakingFlowStepIds.add(sfs.getId());
            });
            if(oldBelongFlowSteps!=null && !oldBelongFlowSteps.isEmpty()){
                Iterator<SpeakingFlowStep> iterator = oldBelongFlowSteps.iterator();
                while (iterator.hasNext()){
                    SpeakingFlowStep speakingFlowStep = iterator.next();
                    if(!speakingFlowStepIds.contains(speakingFlowStep.getId())){
                        needDelFlowSteps.add(speakingFlowStep);
                    }
                }
                //需删除的流程步骤
                if(needDelFlowSteps!=null && !needDelFlowSteps.isEmpty()){
                    ElasticsearchOperation operation = new ElasticsearchOperation(txId,
                            LinkCallTables.SPEAKING_FLOW_STEP.getTableName(),
                            LinkCallOperations.delSpeakingFlowSteps.getOperationName(),
                            needDelFlowSteps);
                    BestDoContextHolder.addOperation(operation);
                }
            }

            ElasticsearchOperation operation = new ElasticsearchOperation(txId,
                    LinkCallTables.SPEAKING_FLOW_STEP.getTableName(),
                    LinkCallOperations.saveorUpdateSpeakingFlowSteps.getOperationName(),
                    speakingFlowSteps);
            BestDoContextHolder.addOperation(operation);
        }
        //主操作
        boolean flag = createDataAndSetVersion(LinkCallRedisVersionKey.TABLE_SPEAKING_FLOW,
                LinkCallTables.SPEAKING_FLOW,
                speakingFlow.getId(),
                speakingFlow.getVersion(),
                ()->speakingFlowRepository.save(speakingFlow));

        if(!flag){
            webResult = new WebResult(GlobalStatic.CODE_N,"保存出错",0,null,null);
        }
        webResult = new WebResult(GlobalStatic.CODE_1,GlobalStatic.SUCCESS_CHAR,0,null,null);
        return  webResult;
    }

}
